////////////////////////////////////////////////////////////////////////////////
//
//  nino
//
////////////////////////////////////////////////////////////////////////////////

package ochart.elements.bars
{
	import caurina.transitions.Tweener;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import ochart.core.ChartBase;
	import ochart.core.ChartObject;
	import ochart.core.ChartObjectFactory;
	import ochart.core.XYChart;
	import ochart.elements.DataElement;
	import ochart.elements.axes.XAxis;
	import ochart.utils.ArrayUtil;
	
	public class BarBase extends DataElement
	{
		public static const CLASS_NAME:String = "BarBase";
		
		override public function get className():String
		{
			return CLASS_NAME;
		}
		
		public static const ALIAS:String = "barBase";
		
		override public function get alias():String
		{
			return ALIAS;
		}
		
		public static const MODE_BAR:String = "bar";
		public static const MODE_CONTAINER:String = "container";
		private var _mode:String = null;

		public function get mode():String
		{
			return _mode;
		}

		public function set mode(value:String):void
		{
			_mode = value;
			isAddToDataElementsArray = (value != MODE_CONTAINER);
		}

		
		public static const STEPS_NAME:String = "steps";
		public var isStepsChange:Boolean = false;
		private var _steps:Number = 1;

		public function get steps():Number
		{
			return _steps;
		}

		public function set steps(value:Number):void
		{
			_steps = value;
			
			needUpdate = true;
		}
		
		public static const VALUES_NAME:String = "values";
		
		public var isValuesChange:Boolean = true;
		private var _values:Array = [];

		public function get values():Array
		{
			return _values;
		}

		public function set values(value:Array):void
		{
			if(!(value is Array))
			{
				value = [];
			}
			_values = value;
			
			isValuesChange = true;
			needRender = true;
		}

		public var barCount:int = 0;
		public var barIndex:int = 0;
		public var barsArray:Array = [];
		public var stepCount:Number = 0;
		public var stepLength:Number = 0;
		
		public var content:DisplayObject = null;
		
		private var defaultValue:Object = 
		{
			"steps" : 1,
			"percentWidth" : 0.8,
			"values" : []
		}
			
		private var _propertiesArray:Array = null;
		
		override public function get propertiesArray():Array
		{
			if(_propertiesArray)
			{
				return _propertiesArray;
			}
			
			_propertiesArray = super.propertiesArray;
			for(var name:String in defaultValue)
			{
				if(!ArrayUtil.containsValue(_propertiesArray, name))
				{
					_propertiesArray.push(name);
				}
			}
			return _propertiesArray;
		}
		
		public function BarBase()
		{
			super();
			
			mode = MODE_CONTAINER;
		}
		
		override public function getDefaultValue(name:String):*
		{
			return (defaultValue[name] === undefined) ? super.getDefaultValue(name) : defaultValue[name];
		}
		
		override public function init():void
		{
			super.init();
			
			barCount = 0;
			barIndex = 0;
			barsArray = [];
		}
		
		override public function update(callAfterUpdate:Boolean=true):Boolean
		{
			if(mode == MODE_CONTAINER && (isValuesChange || isStepsChange))
			{
				isValuesChange = false;
				isStepsChange = false;
				for each(var removeBar:BarBase in barsArray)
				{
					removeChild(removeBar);
				}
				barsArray = [];
				
				if(values.length > 0)
				{
					alpha = 1;
					var chart:XYChart = chart as XYChart;
					stepLength = (chart.xAxis.width - (chart.xAxis.offset * 2)) / (chart.xAxis.max - chart.xAxis.min + steps);
					chart.xAxis.barOffset = stepLength * steps / 2;
					stepCount = Math.ceil((chart.xAxis.max - chart.xAxis.min) / steps) + 1;
					var childData:Object = cloneData([VALUES_NAME, STEPS_NAME]);
					for(var index:int = 0; index < stepCount; index++)
					{
						if(index >= values.length || !values[index])
						{
							continue;
						}
						var barWidth:Number = (index == stepCount - 1) ? (stepLength * (chart.xAxis.max - chart.xAxis.min - (steps * (index - 1)))) : (stepLength * steps);
						var barHeight:Number = chart.yAxis.stepLength * values[index] + chart.yAxis.offset;
						if(barHeight > chart.yAxis.height - chart.yAxis.offset)
						{
							barHeight = chart.yAxis.height - chart.yAxis.offset;
						}
						var childBar:BarBase = ChartObjectFactory.instance.create(alias) as BarBase;
						childBar.mode = MODE_BAR;
						childBar.chart = chart;
						childBar.fromData(childData);
						childBar.value = values[index];
						childBar.height = barHeight;
						childBar.width = barWidth * percentWidth / barCount;
						childBar.x = chart.xAxis.offset + (stepLength * steps * index) + (barWidth * ((1 - percentWidth) / 2)) + (barIndex * childBar.width);
						childBar.y = height - childBar.height;
						childBar.addEventListener(MouseEvent.MOUSE_OVER, onChildBarMouseOver);
						childBar.addEventListener(MouseEvent.MOUSE_OUT, onChildBarMouseOut);
						barsArray.push(childBar);
						addChild(childBar);
					}
					needRender = false;
				}
			}
			
			if(!super.update(false))
			{
				return false;
			}
			
			if(callAfterUpdate)
			{
				return afterUpdate();
			}
			return true;
		}
		
		protected function onChildBarMouseOver(event:MouseEvent):void
		{
			Tweener.addTween(event.target, {alpha:1, time:0.5});
		}
		
		protected function onChildBarMouseOut(event:MouseEvent):void
		{
			Tweener.addTween(event.target, {alpha:(
				(event.target as ChartObject).getSerializationValue("alpha", 1)), 
				time:0.5});
		}
		
		override public function evaluateSpace(point:Point):Number
		{
			var localPoint:Point = this.globalToLocal(point);
			var x:Number = 0;
			var y:Number = 0;
			if(localPoint.x < (width / 2))
			{
				x = 0;
				if(localPoint.x < height / 2)
				{
					y = 0;
				}
				else
				{
					y = height;
				}
			}
			else
			{
				x = width;
				if(localPoint.x < height / 2)
				{
					y = 0;
				}
				else
				{
					y = height;
				}
			}
			return Math.sqrt(Math.pow((localPoint.x - x), 2) + Math.pow((localPoint.y - y), 2))
		}
	}
}